/**
 * 
 * MindBox 2009
 */
package com.mindbox.viajes.dao;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;

import com.mindbox.viajes.db.ConexionDAO;
import com.mindbox.viajes.dto.Ciudad;
import com.mindbox.viajes.dto.Evento;
import com.mindbox.viajes.dto.Pais;
import com.mindbox.viajes.dto.TipoEvento;
import com.mindbox.viajes.exception.ExceptionBaseDatos;
import com.mindbox.viajes.exception.ExceptionLogica;
import com.mindbox.viajes.util.Utilidades;

/**
 * Clase para el acceso a datos de los paises. MindBox 2009
 * 
 * @author Julian
 * 
 */
public class DAOEvento {

	/**
	 * Consulta todos los eventos del sistema. <b>NO SE CONSULTAN LOS
	 * ITINERARIOS PARA CADA EVENTO</b>
	 * 
	 * @return
	 * @throws ExceptionBaseDatos
	 * @author Julian
	 */
	public ArrayList<Evento> getEventos() throws ExceptionBaseDatos {
		/*
		 * Estos arreglos sirven para ir almacenando los paises, ciudades y tipo
		 * de eventos que se van consultando en los eventos. Esto se hace para
		 * no repetir estas entidades.
		 */
		ArrayList<Evento> eventos = new ArrayList<Evento>();
		ArrayList<Pais> paises = new ArrayList<Pais>();
		ArrayList<Ciudad> ciudades = new ArrayList<Ciudad>();
		ArrayList<TipoEvento> tipos = new ArrayList<TipoEvento>();
		ConexionDAO conexion = null;
		ResultSet rs = null;
		try {
			conexion = new ConexionDAO();
			String sql = "SELECT e.*, t.*, c.*, p.* "
					+ "FROM evento AS e "
					+ "INNER JOIN tipo_evento AS t ON t.tipo_evento_id = e.evento_tipo_evento_id "
					+ "INNER JOIN ciudad AS c ON c.ciudad_id = e.evento_ciudad_id "
					+ "INNER JOIN pais AS p ON p.pais_id = c.ciudad_pais_id ";
			rs = conexion.executeQuery(sql);
			while (rs.next()) {
				/*
				 * El proceso es el siguiente: 1. Se asignan las entidades que
				 * conforman un evento: Pais, Ciudad, TipoEvento. 2. Se verifica
				 * si cada entidad se a consultado antes. 3. Si no se ha
				 * consultado se agrega a un arreglo temporal, para ir llevando
				 * el registro. 4. Se verifica si la ciudad ya la tiene el pais,
				 * si no la tiene se le adiciona. 5. Por ultimo se asignan los
				 * valores propios del evento.
				 */
				Pais p = DAOPais.asignarDatosPais(rs);
				Ciudad c = DAOCiudad.asignarDatosCiudad(rs);
				TipoEvento t = DAOTipoEvento.asignarDatosTipoEvento(rs);

				if (!paises.contains(p))
					paises.add(p);
				else
					p = paises.get(paises.indexOf(p));

				// Se le asigna antes, para comparar la ciudad incluyendo el pais
				c.setPais(p);

				if (!ciudades.contains(c))
					ciudades.add(c);
				else
					c = ciudades.get(ciudades.indexOf(c));

				c.setPais(p);

				if (!tipos.contains(t))
					tipos.add(t);
				else
					t = tipos.get(tipos.indexOf(t));

				/*
				 * Se verifica que el pais tenga la ciudad
				 */
				if (!p.getCiudades().contains(c))
					p.getCiudades().add(c);

				Evento e = asignarDatosEvento(rs);
				e.setCiudad(c);
				e.setTipoEvento(t);
				eventos.add(e);
			}
		} catch (Exception e) {
			String msg = "Error al consultar los datos de los eventos";
			System.out.println(msg + ". Mensaje:" + e.getMessage());
			e.printStackTrace();
			throw new ExceptionBaseDatos(msg);
		} finally {
			conexion.cerrarFinal(rs);
			if (conexion != null)
				try {
					conexion.cerrarCon();
				} catch (SQLException e) {
					String msg = "Error al cerrar la BD al consultar eventos";
					System.out.println(msg + ". Mensaje:" + e.getMessage());
					e.printStackTrace();
				}
		}
		return eventos;
	}

	/**
	 * Inserta un evento. <b>EL EVENTO DEBE TENER LOS DATOS DE CIUDAD Y TIPO DE
	 * EVENTO.</b>
	 * 
	 * @param evento
	 * @throws ExceptionBaseDatos
	 * @throws ExceptionLogica
	 * @author Julian
	 */
	public void guardarEvento(Evento evento) throws ExceptionBaseDatos,
			ExceptionLogica {
		ConexionDAO conexion = null;
		PreparedStatement ps = null;
		try {
			conexion = new ConexionDAO();
			String sql = "INSERT INTO evento (evento_nombre, evento_descripcion, evento_fecha_hora_inicio, "
					+ "evento_fecha_hora_fin, evento_ciudad_id, evento_tipo_evento_id, evento_direccion, "
					+ "evento_coordenadas) VALUES(?,?,?,?,?,?,?,?)";

			ps = conexion.getPreparedStatement(sql);
			ps.setString(1, evento.getNombre());
			ps.setString(2, evento.getDescripcion());
			ps.setTimestamp(3, new Timestamp(evento.getFechaHoraInicio()
					.getTime()));
			ps.setTimestamp(4,
					new Timestamp(evento.getFechaHoraFin().getTime()));
			ps.setInt(5, Integer.parseInt(evento.getCiudad().getId()));
			ps.setInt(6, Integer.parseInt(evento.getTipoEvento().getId()));
			ps.setString(7, evento.getDireccion());
			ps.setString(8, evento.getCoordenadas());

			int filas = ps.executeUpdate();
			if (filas <= 0)
				throw new ExceptionLogica("No se pudo insertar el evento");
		} catch (ExceptionLogica e) {
			throw e;
		} catch (Exception e) {
			String msg = "Error al insertar los datos del evento";
			System.out.println(msg + ". Mensaje:" + e.getMessage());
			e.printStackTrace();
			throw new ExceptionBaseDatos(msg);
		} finally {
			conexion.cerrarFinal(ps);
			if (conexion != null)
				try {
					conexion.cerrarCon();
				} catch (SQLException e) {
					String msg = "Error al cerrar la BD al insertar el evento";
					System.out.println(msg + ". Mensaje:" + e.getMessage());
					e.printStackTrace();
				}
		}
	}
		
	/**
	 * Asigna los datos del ResultSet a un objeto Evento.
	 * 
	 * @param rs
	 * @return
	 * @throws SQLException
	 * @author Julian
	 */
	static Evento asignarDatosEvento(ResultSet rs) throws SQLException {
		Evento e = new Evento();
		e.setDescripcion(rs.getString("evento_descripcion"));
		e.setFechaHoraFin(rs.getTimestamp("evento_fecha_hora_fin"));
		e.setFechaHoraInicio(rs.getTimestamp("evento_fecha_hora_inicio"));
		e.setId(rs.getString("evento_id"));
		e.setNombre(rs.getString("evento_nombre"));
		e.setDireccion(rs.getString("evento_direccion"));
		e.setCoordenadas(rs.getString("evento_coordenadas"));
		return e;
	}
	
	/**
	 * Consulta todos los eventos del sistema por fecha
	 * 
	 * @return
	 * @throws ExceptionBaseDatos
	 * @author Catalina Soto Zuluaga
	 */
	public ArrayList<Evento> getEventosPorFecha(String ciudad, String fechaInicio, String fechaFin) throws ExceptionBaseDatos {
	
		ArrayList<Evento> eventos = new ArrayList<Evento>();
		ConexionDAO conexion = null;
		ResultSet rs = null;
		try {
			conexion = new ConexionDAO();
			
			String sql = "SELECT * FROM evento WHERE evento_fecha_hora_inicio between '"
					+ fechaInicio
					+ "' and '"
					+ fechaFin
					+ "' and evento_ciudad_id = " + Integer.parseInt(ciudad);
			rs = conexion.executeQuery(sql);
			while (rs.next()) {
				Evento e = new Evento();
				e.setDescripcion(rs.getString("evento_descripcion"));
				e.setFechaHoraFin(rs.getTimestamp("evento_fecha_hora_fin"));
				e.setFechaHoraInicio(rs
						.getTimestamp("evento_fecha_hora_inicio"));
				e.setId(rs.getString("evento_id"));
				e.setNombre(rs.getString("evento_nombre"));
				e.setDireccion(rs.getString("evento_direccion"));
				e.setCoordenadas(rs.getString("evento_coordenadas"));
				eventos.add(e);
			}
		} catch (Exception e) {
			String msg = "Error al consultar los datos de los eventos";
			System.out.println(msg + ". Mensaje:" + e.getMessage());
			e.printStackTrace();
			throw new ExceptionBaseDatos(msg);
		} finally {
			conexion.cerrarFinal(rs);
			if (conexion != null)
				try {
					conexion.cerrarCon();
				} catch (SQLException e) {
					String msg = "Error al cerrar la BD al consultar eventos";
					System.out.println(msg + ". Mensaje:" + e.getMessage());
					e.printStackTrace();
				}
		}
		return eventos;
	}
}